// ============================================
// 07 - 枚举和模式匹配 (Enums and Pattern Matching)
// ============================================

/// 枚举允许列举可能的成员来定义一个类型

// ==================== 定义枚举 ====================

/// 基本枚举
#[derive(Debug)]
enum IpAddrKind {
    V4,
    V6,
}

pub fn basic_enums() {
    println!("\n=== 基本枚举 ===");
    
    let four = IpAddrKind::V4;
    let six = IpAddrKind::V6;
    
    println!("IPv4: {:?}", four);
    println!("IPv6: {:?}", six);
    
    route(IpAddrKind::V4);
    route(IpAddrKind::V6);
}

fn route(ip_kind: IpAddrKind) {
    println!("路由 IP 类型: {:?}", ip_kind);
}

/// 枚举值
/// 枚举成员可以携带数据
#[derive(Debug)]
enum IpAddr {
    V4(u8, u8, u8, u8),
    V6(String),
}

pub fn enum_with_data() {
    println!("\n=== 带数据的枚举 ===");
    
    let home = IpAddr::V4(127, 0, 0, 1);
    let loopback = IpAddr::V6(String::from("::1"));
    
    println!("家庭地址: {:?}", home);
    println!("回环地址: {:?}", loopback);
}

/// 多种类型的枚举成员
#[derive(Debug)]
enum Message {
    Quit,                       // 没有关联数据
    Move { x: i32, y: i32 },   // 匿名结构体
    Write(String),              // String
    ChangeColor(i32, i32, i32), // 三个 i32
}

pub fn various_enum_types() {
    println!("\n=== 多种类型的枚举 ===");
    
    let msg1 = Message::Quit;
    let msg2 = Message::Move { x: 10, y: 20 };
    let msg3 = Message::Write(String::from("hello"));
    let msg4 = Message::ChangeColor(255, 0, 0);
    
    println!("{:?}", msg1);
    println!("{:?}", msg2);
    println!("{:?}", msg3);
    println!("{:?}", msg4);
}

/// 为枚举定义方法
impl Message {
    fn call(&self) {
        match self {
            Message::Quit => println!("退出消息"),
            Message::Move { x, y } => println!("移动到 ({}, {})", x, y),
            Message::Write(text) => println!("写入文本: {}", text),
            Message::ChangeColor(r, g, b) => println!("改变颜色到 RGB({}, {}, {})", r, g, b),
        }
    }
}

pub fn enum_methods() {
    println!("\n=== 枚举方法 ===");
    
    let msg = Message::Write(String::from("Hello"));
    msg.call();
    
    Message::Move { x: 10, y: 20 }.call();
}

// ==================== Option 枚举 ====================

/// Option 枚举处理可能为空的值
/// Rust 没有 null，使用 Option<T> 代替
pub fn option_enum() {
    println!("\n=== Option 枚举 ===");
    
    // Some 和 None
    let some_number = Some(5);
    let some_string = Some("a string");
    let absent_number: Option<i32> = None;
    
    println!("有值: {:?}", some_number);
    println!("有值: {:?}", some_string);
    println!("无值: {:?}", absent_number);
    
    // Option<T> 和 T 是不同的类型
    let x: i8 = 5;
    let y: Option<i8> = Some(5);
    
    // let sum = x + y; // ❌ 错误: 不能直接相加
    
    // 必须先处理 Option
    if let Some(value) = y {
        let sum = x + value;
        println!("x + y = {}", sum);
    }
}

pub fn option_methods() {
    println!("\n=== Option 方法 ===");
    
    let some_number = Some(5);
    
    // is_some() 和 is_none()
    println!("is_some: {}", some_number.is_some());
    println!("is_none: {}", some_number.is_none());
    
    // unwrap() - 提取值，如果是 None 会 panic
    let value = some_number.unwrap();
    println!("unwrap: {}", value);
    
    // unwrap_or() - 提供默认值
    let none_number: Option<i32> = None;
    let value = none_number.unwrap_or(0);
    println!("unwrap_or: {}", value);
    
    // map() - 转换 Option 中的值
    let some_string = Some("hello");
    let some_len = some_string.map(|s| s.len());
    println!("map: {:?}", some_len);
    
    // and_then() - 链式调用
    let result = Some(2).and_then(|x| Some(x * 2));
    println!("and_then: {:?}", result);
}

// ==================== match 表达式 ====================

/// match 控制流
pub fn match_control_flow() {
    println!("\n=== match 控制流 ===");
    
    let coin = Coin::Quarter(UsState::Alaska);
    let value = value_in_cents(coin);
    println!("硬币价值: {} 美分", value);
}

#[derive(Debug)]
enum UsState {
    Alabama,
    Alaska,
    // ... 其他州
}

enum Coin {
    Penny,
    Nickel,
    Dime,
    Quarter(UsState),
}

fn value_in_cents(coin: Coin) -> u8 {
    match coin {
        Coin::Penny => {
            println!("幸运便士!");
            1
        }
        Coin::Nickel => 5,
        Coin::Dime => 10,
        Coin::Quarter(state) => {
            println!("州硬币来自 {:?}!", state);
            25
        }
    }
}

/// 匹配 Option<T>
pub fn matching_option() {
    println!("\n=== 匹配 Option ===");
    
    let five = Some(5);
    let six = plus_one(five);
    let none = plus_one(None);
    
    println!("plus_one(Some(5)): {:?}", six);
    println!("plus_one(None): {:?}", none);
}

fn plus_one(x: Option<i32>) -> Option<i32> {
    match x {
        None => None,
        Some(i) => Some(i + 1),
    }
}

/// 通配符和 _ 占位符
pub fn catch_all_patterns() {
    println!("\n=== 通配符模式 ===");
    
    let dice_roll = 9;
    match dice_roll {
        3 => println!("获得特殊道具"),
        7 => println!("失去特殊道具"),
        other => println!("移动 {} 步", other), // 捕获其他值
    }
    
    let dice_roll = 5;
    match dice_roll {
        3 => println!("获得特殊道具"),
        7 => println!("失去特殊道具"),
        _ => (), // 忽略其他值
    }
}

// ==================== if let ====================

/// if let 简洁控制流
pub fn if_let_syntax() {
    println!("\n=== if let 语法 ===");
    
    let config_max = Some(3u8);
    
    // 使用 match
    match config_max {
        Some(max) => println!("最大值是 {}", max),
        _ => (),
    }
    
    // 使用 if let 更简洁
    if let Some(max) = config_max {
        println!("最大值是 {}", max);
    }
    
    // if let 配合 else
    let config_max: Option<u8> = None;
    if let Some(max) = config_max {
        println!("最大值是 {}", max);
    } else {
        println!("没有配置最大值");
    }
}

// ==================== 高级模式匹配 ====================

/// 解构结构体
#[derive(Debug)]
struct Point {
    x: i32,
    y: i32,
}

pub fn destructuring_structs() {
    println!("\n=== 解构结构体 ===");
    
    let p = Point { x: 0, y: 7 };
    
    let Point { x, y } = p;
    println!("x = {}, y = {}", x, y);
    
    // 使用不同的变量名
    let Point { x: a, y: b } = p;
    println!("a = {}, b = {}", a, b);
    
    // 在 match 中解构
    match p {
        Point { x: 0, y } => println!("在 y 轴上，y = {}", y),
        Point { x, y: 0 } => println!("在 x 轴上，x = {}", x),
        Point { x, y } => println!("不在坐标轴上: ({}, {})", x, y),
    }
}

/// 解构嵌套的结构体和枚举
#[derive(Debug)]
enum Color {
    Rgb(i32, i32, i32),
    Hsv(i32, i32, i32),
}

#[derive(Debug)]
enum Message2 {
    Quit,
    Move { x: i32, y: i32 },
    Write(String),
    ChangeColor(Color),
}

pub fn destructuring_nested() {
    println!("\n=== 解构嵌套结构 ===");
    
    let msg = Message2::ChangeColor(Color::Rgb(255, 0, 0));
    
    match msg {
        Message2::ChangeColor(Color::Rgb(r, g, b)) => {
            println!("改变颜色为 RGB({}, {}, {})", r, g, b);
        }
        Message2::ChangeColor(Color::Hsv(h, s, v)) => {
            println!("改变颜色为 HSV({}, {}, {})", h, s, v);
        }
        Message2::Move { x, y } => {
            println!("移动到 ({}, {})", x, y);
        }
        _ => println!("其他消息"),
    }
}

/// 忽略值
pub fn ignoring_values() {
    println!("\n=== 忽略值 ===");
    
    // 使用 _ 忽略整个值
    let numbers = (2, 4, 8, 16, 32);
    match numbers {
        (first, _, third, _, fifth) => {
            println!("匹配的数字: {}, {}, {}", first, third, fifth);
        }
    }
    
    // 使用 .. 忽略剩余部分
    let numbers = (2, 4, 8, 16, 32);
    match numbers {
        (first, .., last) => {
            println!("第一个: {}, 最后一个: {}", first, last);
        }
    }
}

/// @ 绑定
pub fn at_bindings() {
    println!("\n=== @ 绑定 ===");
    
    let msg = Message3::Hello { id: 5 };
    
    match msg {
        Message3::Hello {
            id: id_variable @ 3..=7,
        } => println!("找到 id 在范围内: {}", id_variable),
        Message3::Hello { id: 10..=12 } => {
            println!("找到 id 在另一个范围内");
        }
        Message3::Hello { id } => println!("找到其他 id: {}", id),
    }
}

enum Message3 {
    Hello { id: i32 },
}

// ==================== Result 枚举 ====================

/// Result 枚举用于错误处理
pub fn result_enum() {
    println!("\n=== Result 枚举 ===");
    
    let good_result: Result<i32, String> = Ok(10);
    let bad_result: Result<i32, String> = Err(String::from("出错了"));
    
    println!("成功结果: {:?}", good_result);
    println!("错误结果: {:?}", bad_result);
    
    // 处理 Result
    match good_result {
        Ok(value) => println!("成功，值为: {}", value),
        Err(e) => println!("失败，错误: {}", e),
    }
    
    // 使用 unwrap_or
    let value = bad_result.unwrap_or(-1);
    println!("使用 unwrap_or: {}", value);
}

/// 实际应用示例
#[derive(Debug)]
enum TrafficLight {
    Red,
    Yellow,
    Green,
}

impl TrafficLight {
    fn time(&self) -> u8 {
        match self {
            TrafficLight::Red => 60,
            TrafficLight::Yellow => 3,
            TrafficLight::Green => 55,
        }
    }
}

pub fn practical_example() {
    println!("\n=== 实际应用: 交通灯 ===");
    
    let lights = vec![
        TrafficLight::Red,
        TrafficLight::Yellow,
        TrafficLight::Green,
    ];
    
    for light in lights.iter() {
        println!("{:?} 灯持续 {} 秒", light, light.time());
    }
}

/// 主函数 - 演示所有功能
#[allow(dead_code)]
pub fn main() {
    println!("╔════════════════════════════════════════╗");
    println!("║   Rust 枚举和模式匹配教程              ║");
    println!("╚════════════════════════════════════════╝");
    
    basic_enums();
    enum_with_data();
    various_enum_types();
    enum_methods();
    option_enum();
    option_methods();
    match_control_flow();
    matching_option();
    catch_all_patterns();
    if_let_syntax();
    destructuring_structs();
    destructuring_nested();
    ignoring_values();
    at_bindings();
    result_enum();
    practical_example();
    
    println!("\n✅ 枚举和模式匹配教程完成！");
}

#[cfg(test)]
mod tests {
    use super::*;
    
    #[test]
    fn test_value_in_cents() {
        assert_eq!(value_in_cents(Coin::Penny), 1);
        assert_eq!(value_in_cents(Coin::Nickel), 5);
        assert_eq!(value_in_cents(Coin::Dime), 10);
    }
    
    #[test]
    fn test_plus_one() {
        assert_eq!(plus_one(Some(5)), Some(6));
        assert_eq!(plus_one(None), None);
    }
    
    #[test]
    fn test_option_unwrap_or() {
        let some = Some(5);
        let none: Option<i32> = None;
        assert_eq!(some.unwrap_or(0), 5);
        assert_eq!(none.unwrap_or(0), 0);
    }
}

